package org.happycomp.radio.scheduler.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Timer;

import org.happycomp.radio.downloader.Downloader;
import org.happycomp.radio.downloader.DownloadingItem;
import org.happycomp.radio.downloader.impl.DownloaderImpl;
import org.happycomp.radio.planner.Planner;
import org.happycomp.radio.planner.impl.PlannerImpl;
import org.happycomp.radio.scheduler.Scheduler;
import org.happycomp.radio.scheduler.SchedulerListener;
import org.happycomp.radio.scheduler.SchedulerTask;

public class SchedulerImpl implements Scheduler {

	public static final java.util.logging.Logger LOGGER = java.util.logging.Logger
			.getLogger(SchedulerImpl.class.getName());
	
	private Timer timer;
	private int interval = 10000;
	private List<SchedulerListener> listeners;
	private Downloader downloader;
	private Planner planner;
	private boolean started = false;

	private Date shutdownDate;
	
	
	public SchedulerImpl() {
		super();
		this.timer = new Timer(true);
		this.downloader = new DownloaderImpl(this);
		this.planner = new PlannerImpl(this);
		this.listeners = new ArrayList<SchedulerListener>();
	}
	
	
	@Override
	public void scheduleCheck() {
		LOGGER.info("Scheduling next task.. Current instance :"+System.identityHashCode(this));
		SchedulerTask task = new SchedulerTask(this, this.planner);
		this.timer.schedule(task, this.interval);
		LOGGER.info("Shutdown date :"+this.shutdownDate);
		if ((this.shutdownDate != null) && (new Date().after(this.shutdownDate))) {
			LOGGER.info("firing shutdown ... ");
			this.fireShutDown();
		}
		
		this.fireRefreshIterval();
	}


	public void fireStopDownloading(DownloadingItem item) {
		try {
			this.planner.getPlannerLock().lock();
			for (SchedulerListener listener : this.listeners) {
				listener.stopDownloading(item);
			}
		} finally {
			this.planner.getPlannerLock().unlock();
		}
		
	}

	public void fireRefreshIterval() {
		try {
			this.planner.getPlannerLock().lock();
			for (SchedulerListener listener : this.listeners) {
				listener.refreshInterval();
			}
		} finally {
			this.planner.getPlannerLock().unlock();
		}
		
	}

	

	@Override
    public void fireException(Throwable throwable) {
        try {
            this.planner.getPlannerLock().lock();
            for (SchedulerListener listener : this.listeners) {
                listener.exceptionOccured(throwable);
            }
        } finally {
            this.planner.getPlannerLock().unlock();
        }
        
    }


    public void fireStartDownloading() {
		try {
			this.planner.getPlannerLock().lock();
			for (SchedulerListener listener : this.listeners) {
				listener.startDownloading();
			}
		} finally {
			this.planner.getPlannerLock().unlock();
		}
		
	}

    
    public void fireShutDown() {
		try {
			this.planner.getPlannerLock().lock();
			for (SchedulerListener listener : this.listeners) {
				listener.shutDown();
			}
		} finally {
			this.planner.getPlannerLock().unlock();
		}
    	
    }



	@Override
	public void addSchedulerListener(SchedulerListener listener) {
		this.listeners.add(listener);
	}



	@Override
	public void removeSchedulerListener(SchedulerListener listener) {
		this.listeners.remove(listener);
	}



	@Override
	public SchedulerListener[] getSchedulerListeners() {
		return (SchedulerListener[]) this.listeners.toArray(new SchedulerListener[this.listeners.size()]);
	}


	@Override
	public Downloader getDownloader() {
		return this.downloader;
	}
	
	@Override
	public Planner getPlanner() {
		return this.planner;
	}

	public boolean isStarted() {
		return this.started;
	}

	


	@Override
	public void start() {
		try {
			this.planner.getPlannerLock().lock();
			if (!this.started) {
				this.started = true;
				this.scheduleCheck();
			}
		} finally {
			this.planner.getPlannerLock().unlock();
		}
		
	}


	@Override
	public void setShutdownSystemDate(Date date) {
		this.shutdownDate = date;
	}


	@Override
	public Date getShutdownSystemDate() {
		return this.shutdownDate;
	}
}
